package gamejam.platformer;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.KeyEvent;

public class Player {
	private Image image;
	private Rectangle bounds;
	private boolean movingLeft = false;
	private boolean movingRight = false;
	private boolean jumping = false;
	private int jumpVel = 0;
	private Map map;
	private boolean inverseGravity = false;
	private MovingPlatform attached = null;
	public Player(Image img, Map m) {
		image = img;
		map = m;
		bounds = new Rectangle(map.getStartPosition(), new Dimension(Map.TILE_SIZE, Map.TILE_SIZE));
	}
	public boolean attachToMovingPlatform() {
		if (inverseGravity && !canMoveUp(1)) {
			Tile t1 = map.getTileAtPosition(bounds.x, bounds.y - 1);
			Tile t2 = map.getTileAtPosition(bounds.x + bounds.width - 1, bounds.y - 1);
			Rectangle next = new Rectangle(bounds.x, bounds.y - 1, bounds.width, bounds.height);
			if (t1 != null && t1 instanceof MovingPlatform && t1.getBounds().intersects(next)) {
				attached = (MovingPlatform) t1;
				attached.attach(this);
				return true;
			} else if (t2 != null && t2 instanceof MovingPlatform && t2.getBounds().intersects(next)) {
				attached = (MovingPlatform) t2;
				attached.attach(this);
				return true;
			}
		} else if (!canMoveDown(1)) {
			Tile t1 = map.getTileAtPosition(bounds.x, bounds.y + bounds.height + 1);
			Tile t2 = map.getTileAtPosition(bounds.x + bounds.width - 1, bounds.y + bounds.height);
			Rectangle next = new Rectangle(bounds.x, bounds.y + 1, bounds.width, bounds.height);
			if (t1 != null && t1 instanceof MovingPlatform && t1.getBounds().intersects(next)) {
				attached = (MovingPlatform) t1;
				attached.attach(this);
				return true;
			} else if (t2 != null && t2 instanceof MovingPlatform && t2.getBounds().intersects(next)) {
				attached = (MovingPlatform) t2;
				attached.attach(this);
				return true;
			}
		}
		if (attached != null) {
			attached.dettach();
			attached = null;
		}
		return false;
	}
	public boolean canMoveDown(int amount) {
		Tile t1 = map.getTileAtPosition(bounds.x, bounds.y + bounds.height + amount);
		Tile t2 = map.getTileAtPosition(bounds.x + bounds.width - 1, bounds.y + bounds.height + amount - 1);
		Rectangle next = new Rectangle(bounds.x, bounds.y + amount, bounds.width, bounds.height);
		return (t1 == null || !t1.getBounds().intersects(next)) && (t2 == null || !t2.getBounds().intersects(next));
	}
	public boolean canMoveLeft(int amount) {
		Tile t1 = map.getTileAtPosition(bounds.x - amount, bounds.y);
		Tile t2 = map.getTileAtPosition(bounds.x - amount, bounds.y + bounds.height - 1);
		Rectangle next = new Rectangle(bounds.x - amount, bounds.y, bounds.width, bounds.height);
		return (t1 == null || !t1.getBounds().intersects(next)) && (t2 == null || !t2.getBounds().intersects(next));
	}
	public boolean canMoveRight(int amount) {
		Tile t1 = map.getTileAtPosition(bounds.x + bounds.width + amount - 1, bounds.y);
		Tile t2 = map.getTileAtPosition(bounds.x + bounds.width + amount - 1, bounds.y + bounds.height - 1);
		Rectangle next = new Rectangle(bounds.x + amount, bounds.y, bounds.width, bounds.height);
		return (t1 == null || !t1.getBounds().intersects(next)) && (t2 == null || !t2.getBounds().intersects(next));
	}
	public boolean canMoveUp(int amount) {
		Tile t1 = map.getTileAtPosition(bounds.x, bounds.y - amount);
		Tile t2 = map.getTileAtPosition(bounds.x + bounds.width - 1, bounds.y - amount);
		Rectangle next = new Rectangle(bounds.x, bounds.y - amount, bounds.width, bounds.height);
		return (t1 == null || !t1.getBounds().intersects(next)) && (t2 == null || !t2.getBounds().intersects(next));
	}
	public void draw(Graphics g) {
		g.drawImage(image, bounds.x - map.getViewport().x, bounds.y - map.getViewport().y, bounds.width, bounds.height, null);
	}
	public void drawBoundingBox(Graphics g) {
		g.setColor(Color.GREEN);
		g.drawRect(bounds.x - map.getViewport().x, bounds.y - map.getViewport().y, bounds.width - 1, bounds.height - 1);
	}
	public Rectangle getBounds() {
		return bounds;
	}
	public int getCenterX() {
		return (int) bounds.getCenterX();
	}
	public int getCenterY() {
		return (int) bounds.getCenterY();
	}
	public int getHeight() {
		return bounds.height;
	}
	public int getWidth() {
		return bounds.width;
	}
	public int getX() {
		return bounds.x;
	}
	public int getY() {
		return bounds.y;
	}
	public boolean isTouchingLava() {
		return false;
	}
	public void keyPressed(KeyEvent e) {
		switch (e.getKeyCode()) {
			case KeyEvent.VK_A:
				movingLeft = true;
				break;
			case KeyEvent.VK_D:
				movingRight = true;
				break;
			case KeyEvent.VK_W:				
				if (!jumping) {
					if (inverseGravity ? !canMoveUp(1) : !canMoveDown(1)) {
						jumping = true;
						jumpVel = bounds.height * 3 / 5;
					}
				}
				break;
		}
	}
	public void keyReleased(KeyEvent e) {
		switch (e.getKeyCode()) {
			case KeyEvent.VK_A:
				movingLeft = false;
				break;
			case KeyEvent.VK_D:
				movingRight = false;
				break;
			case KeyEvent.VK_S:
				inverseGravity = !inverseGravity;
				break;
		}
	}
	public void setPosition(Point p) {
		bounds.setLocation(p);
	}
	public void setX(int x) {
		bounds.x = x;
	}
	public void setY(int y) {
		bounds.y = y;
	}
	public void tick() {
		if (movingLeft) {
			int x;
			for (x = bounds.width / 10; x > 0; x--)
				if (canMoveLeft(x))
					break;
			bounds.x -= x;
		}
		if (movingRight) {
			int x;
			for (x = bounds.width / 10; x > 0; x--)
				if (canMoveRight(x))
					break;
			bounds.x += x;
		}
		if (jumping) {
			int y;
			for (y = jumpVel; y > 0; y--)
				if (inverseGravity ? canMoveDown(y) : canMoveUp(y))
					break;
			bounds.y -= inverseGravity ? -y : y;
			jumpVel = jumpVel * 9 / 10;
			if (jumpVel == 0)
				jumping = false;
		} else {
			int y;
			for (y = bounds.height / 5; y > 0; y--)
				if (inverseGravity ? canMoveUp(y) : canMoveDown(y))
					break;
			bounds.y += inverseGravity ? -y : y;
		}
		attachToMovingPlatform();
	}
	public String toString() {
		return String.format("%s[x=%s, y=%s, w=%s, h=%s]", this.getClass().getCanonicalName(),
				bounds.x, bounds.y, bounds.width, bounds.height);
	}
}
